﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework;

namespace BlackStar
{
    public class FontContentReader : ContentTypeReader<Font>
    {
        protected override Font Read(ContentReader input, Font existingInstance)
        {
            Font font = new Font();
            font.AssetName = input.ReadString();
            font.Load(input);
            return font;
        }
    }

    public class Font
    {
        public string AssetName;
        internal SpriteFont font;

        internal void Load(ContentReader input)
        {
            string assetDir = input.AssetName.Substring(0, input.AssetName.LastIndexOf("\\") + 1);
            font = input.ContentManager.Load<SpriteFont>(assetDir + this.AssetName);
        }
    }

    public class FontListContentReader : ContentTypeReader<FontList>
    {
        protected override FontList Read(ContentReader input, FontList existingInstance)
        {
            FontList list = new FontList();
            int count = input.ReadInt32();
            for (int i = 0; i < count; i++)
            { list.Add(input.ReadString(), input.ReadObject<Font>()); }

            if (!list.ContainsKey("Default"))
            { throw new ApplicationException("A Default font must be specified."); }

            return list;
        }
    }

    public class FontList : Dictionary<string, Font>
    {
        internal GUI myGui;
        
        public new Font this[string key]
        {
            get
            {
                if (this.ContainsKey(key))
                { return base[key]; }
                else
                { return base["Default"]; }
            }
            set { base[key] = value; }
        }


        public void Draw(string font, string text, Vector2 position, Color color)
        {
            myGui.batch.DrawString(this[font].font, text, position, color);
        }

        public void Draw(string font, string text, Rectangle rect, Color color)
        {
            string shorttext;
            shorttext = TrimText(text, this[font].font, rect);
            myGui.batch.DrawString(this[font].font, shorttext, new Vector2(rect.X, rect.Y), color);
        }

        private string TrimText(string text, SpriteFont font, Rectangle rect)
        {
            // currently only supports a single line.
            string result = text;
            Vector2 strSize = font.MeasureString(result);
            Vector2 interiorSize = new Vector2(rect.Width, rect.Height);

            while (strSize.X > interiorSize.X)
            {
                result = result.Substring(0, result.Length - 1);
                strSize = font.MeasureString(result);
            }
            return result;
        }

        public void DrawCursor(int pos, string text, string font, Rectangle rect, Color color)
        {
            //int newPos = (pos <= text.Length) ? pos : text.Length;
            Vector2 vPos = this[font].font.MeasureString(text.Substring(0, pos));
            myGui.DrawRectangle(new Rectangle(rect.X + (int)(vPos.X), rect.Y, 1, rect.Height), color);
        }

        public float CursorPos(int pos, string text, string font)
        {
            //int newPos = (pos <= text.Length) ? pos : text.Length;
            return this[font].font.MeasureString(text.Substring(0, pos)).X;
        }

        [ContentSerializerIgnore]
        public GUI GUI
        {
            get { return myGui; }
            set { myGui = value; }
        }

        public int CursorPos(string font, string text, Point pos, Rectangle rect)
        {
            string strPart = text;

            if (pos.X >= rect.Right) return text.Length -1;
            if (pos.X < rect.X) return -1;

            int clickLen = pos.X - rect.X;
            if (clickLen < 0) { return -1; }
            
            Vector2 nextLen = MeasureString(font, strPart.Substring(0, strPart.Length - 1));
            Vector2 len = MeasureString(font, strPart);

            while ((nextLen.X > (clickLen)) && (strPart.Length > 1))
            {
                strPart = strPart.Substring(0, strPart.Length - 1);
                nextLen = MeasureString(font, strPart.Substring(0, strPart.Length - 1));
                len = MeasureString(font, strPart);
            }

            // now we need to decide which is closer to pos, len or nextLen.
            float lenDiff = Math.Abs(clickLen - len.X);
            float nextDiff = Math.Abs(clickLen - nextLen.X);

            return (lenDiff < nextDiff) ? strPart.Length : strPart.Length - 1;
        }

        public int LinesFitting(string font, int height)
        {
            int result = 0;
            string tmp = "A";
            Vector2 drawsize;
            do
            {
                drawsize = this[font].font.MeasureString(tmp);
                tmp += "\nA";
                result++;
            } while ((int)drawsize.Y < height);
            return result - 1;
        }

        public Vector2 MeasureString(string font, string text)
        { return this[font].font.MeasureString(text); }
    }
}
